package com.zx._09_架构.rpc演变过程.rpc_03;

import com.zx.common.entity.UserRpcDto;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;

// 优化1：Stub 是 consumer 端的代理对象，负责网络的连接、请求数据发送、响应接受、数据封装等
// 优化2： 进阶为动态代理
public class Stub {

    public static <T> T getProxy(final Class<T> clazz) {
        // 动态代理，需要去执行的代码
        final InvocationHandler h = new InvocationHandler() {
            @Override
            public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
                final Socket socket;
                try {
                    socket = new Socket("localhost", 8888);
                    final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                    final DataOutputStream output = new DataOutputStream(outputStream);
                    output.writeLong(Long.parseLong(args[0].toString()));

                    final OutputStream socketOut = socket.getOutputStream();
                    socketOut.write(outputStream.toByteArray());
                    socketOut.flush();

                    final InputStream inputStream = socket.getInputStream();
                    final DataInputStream input = new DataInputStream(inputStream);
                    final long id = input.readLong();
                    final String name = input.readUTF();
                    final UserRpcDto userRpcDto = new UserRpcDto(id, name);
                    outputStream.close();
                    socket.close();
                    return userRpcDto;
                } catch (final IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        };

        final Object object = Proxy.newProxyInstance(clazz.getClassLoader(),
                new Class[]{clazz}, h);

        return (T) object;
    }

}
